package com.mydemo.spring.dynamicroutes.config;

import com.mydemo.spring.dynamicroutes.entity.MyRoute;
import com.mydemo.spring.dynamicroutes.support.MyRouteLocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.gateway.support.WeightConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Flux;



/**
 * @name 路由配置
 * @auth DIY
 * @date 2020/10/13 17:31
 **/
@Configuration
public class MyRouteConfig {


    private final Logger log = LoggerFactory.getLogger(MyRouteConfig.class);


    private RouteLocatorBuilder routeLocatorBuilder;
    private MyRouteLocator myRouteLocator;

    public MyRouteConfig(RouteLocatorBuilder builder) {
        this.routeLocatorBuilder = builder;
    }

    @Bean("myRouteLocator")
    public MyRouteLocator loadRoutes() {
        MyRoute myRoute1 = new MyRoute("route001", "group01", 10, "/route/server/*", "http://127.0.0.1:8080");
        MyRoute myRoute2 = new MyRoute("route002", "group01", 10, "/route/server/*", "http://127.0.0.1:8081");
        Flux<Route> routeFlux = buildRoutes(myRoute1, myRoute2);
        myRouteLocator = MyRouteLocator.build(routeFlux);
        return myRouteLocator;
    }

    public void addRoutes(MyRoute... routes){
        Flux<Route> routeFlux = buildRoutes(routes);
        myRouteLocator.add(routeFlux);
    }

    public void delRoutes(String... routeIds){
        for (String routeId : routeIds) {
            myRouteLocator.del(routeId);
        }
    }

    private Flux<Route> buildRoutes(MyRoute... routes){
        RouteLocatorBuilder.Builder routeBuilder = routeLocatorBuilder.routes();
        for (MyRoute route : routes) {
            if (null == route){
                continue;
            }
            buildRouteByInstanceData(route, routeBuilder);
        }
        return routeBuilder.build().getRoutes();
    }



    /**
     * 为方便按相同方式创建路由: 当前方法只是根据路由builder定义好了路由,需要routeBuilder调用build方法才正式生成路由
     * @param route
     * @param routeBuilder
     */
    private void buildRouteByInstanceData(MyRoute route, RouteLocatorBuilder.Builder routeBuilder) {
        WeightConfig weightConfig = new WeightConfig(route.getRouteGroup(), route.getRouteId(), route.getRouteWeight());
        log.debug("初始化路由数据: {}", weightConfig);
        routeBuilder.route(route.getRouteId(),
                //TODO 1.按请求路径格式匹配(gateway自带判定方式)
                r -> r.path(route.getRoutePathPattern())
                        .and()
                        .predicate(exchange -> {
                            //TODO 2.自定义路由进入条件
                            return true;
                        })
                        .and()
                        //TODO 3.按分组的权重路由
                        .weight(route.getRouteGroup(), route.getRouteWeight())
                        .filters(f -> f
                                .filter((exchange, chain) -> {
                                    //TODO 4.自定义过滤器
                                    return chain.filter(exchange);
                                })
                                //TODO 5.失败重试(gateway自带过滤器)
                                .retry(retryConfig -> {
                                    retryConfig.setRetries(3);
                                })
                        )
                        .uri(route.getRouteUri())
                        //TODO 6.路由可额外保存一些参数到路由中
                        .metadata(MyRouteLocator.ROUTE_WEIGHT_CONFIG, weightConfig));
    }























}
